//
// OpenTemplate Compiler
// Copyright (c) 2006
// by OpenArrow Software ( http://www.openarrow.com )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.
//

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Reflection;

using OpenArrow.Reporting;
using OpenArrow.Templating.Directives;
using OpenArrow.Templating.Parsing;
using OpenArrow.Utils;

namespace OpenArrow.Templating.Compiler
{
    class Program
    {
        static string[] templateExtensions = new string[] { ".otx", ".ot", ".template" };

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object,System.Object)")]
        static void Main(string[] args)
        {
            Console.WriteLine("OpenArrow Template Compiler v{0}", Assembly.GetExecutingAssembly().GetName().Version.ToString());
            Console.WriteLine("Copyright (c) 2006 OpenArrow Software");
            Console.WriteLine("Licensed under the terms of the Common Public License");
            Console.WriteLine();

            ProcessorResults results = CompileTemplates(args);

            Console.WriteLine();

            int errorCount = 0;
            int warningCount = 0;
            if (results.GeneralProblems.Count > 0)
            {
                RenderProblems("General", results.GeneralProblems);
                errorCount += results.GeneralProblems.ErrorCount;
                warningCount += results.GeneralProblems.WarningCount;
            }
            foreach (KeyValuePair<string, IndividualProcessorResults> indResults in results.IndividualResults)
            {
                if (indResults.Value.Problems.Count > 0)
                    RenderProblems(indResults.Key, indResults.Value.Problems);
                errorCount += indResults.Value.Problems.ErrorCount;
                warningCount += indResults.Value.Problems.WarningCount;
            }
            string message = "Compilation Succeeded";
            if (!results.Success)
                message = "Compilation Failed";
            Console.WriteLine(String.Format("{0} - {1} error(s), {2} warning(s)", message, errorCount, warningCount));
            Console.ReadLine();
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object)")]
        private static void RenderProblems(string fileName, ProblemCollection problemCollection)
        {
            foreach (Problem problem in problemCollection)
                Console.WriteLine(String.Format("{0} {1}", fileName, problem.ToString()));
        }

        private static ProcessorResults CompileTemplates(string[] args)
        {
            // Read in the arguments: [input files] (-[argument] [value])*
            CommandLineParser cmdline = null;
            try
            {
                cmdline = new CommandLineParser(args);
            }
            catch (IOException)
            {
                ProcessorResults res = new ProcessorResults();
                res.GeneralProblems.Add(Problem.Error_CouldNotParseResponseFile());
                return res;
            }

            // Setup Processor Paramaters
            ProcessorParameters parameters = new ProcessorParameters();
            parameters.CodeDirectory = GetNamedArguement(cmdline, Environment.CurrentDirectory, "Code", "CodeDirectory", "C");
            parameters.CompileAssembly = !GetSwitch(cmdline, false, "Generate", "G");
            parameters.TemplateFileExtensions.Clear();
            parameters.TemplateFileExtensions.AddRange(templateExtensions);

            // Setup Compiler Parameters
            parameters.CompilerParameters.GenerateExecutable = GetSwitch(cmdline, false, "Exe", "EXE", "X");
            parameters.CompilerParameters.GenerateInMemory = false;
            parameters.CompilerParameters.IncludeDebugInformation = GetSwitch(cmdline, false, "Debug", "D");
            parameters.CompilerParameters.MainClass = GetNamedArguement(cmdline, null, "MainClass", "M");
            parameters.CompilerParameters.OutputAssembly = GetNamedArguement(cmdline, "CompiledTemplates.dll", "Output", "O");
            parameters.CompilerParameters.TreatWarningsAsErrors = GetSwitch(cmdline, false, "WarningsAsErrors", "W");
            int warnLevel = 0;
            if (Int32.TryParse(GetNamedArguement(cmdline, String.Empty, "WarningLevel", "Warn", "L"), out warnLevel))
                parameters.CompilerParameters.WarningLevel = warnLevel;
            parameters.CompilerParameters.Win32Resource = GetNamedArguement(cmdline, null, "Win32Resource");

            // Setup input paths
            BuildPathList(cmdline, parameters.CompilerParameters.EmbeddedResources, "EmbeddedResource", "Res", "Resource");
            BuildPathList(cmdline, parameters.CompilerParameters.LinkedResources, "LinkedResource", "L");
            BuildAssemblyPathList(cmdline, parameters.CompilerParameters.ReferencedAssemblies, "Reference", "R");

            // Process the templates
            return TemplateProcessor.ProcessFiles(cmdline.UnnamedArguments.ToArray(), parameters, 
                new SimpleOutputReporter(Console.Out));
        }
        
        private static bool GetSwitch(CommandLineParser cmdline, bool defaultValue, params string[] switches)
        {
            bool value = defaultValue;
            foreach (string @switch in switches)
                value = value || cmdline.Switches.Contains(@switch);
            return value;
        }

        private static string GetNamedArguement(CommandLineParser cmdline, string defaultValue, params string[] names)
        {
            string value = defaultValue;
            foreach (string name in names)
            {
                string curVal = cmdline.NamedArguments[name];
                if (!String.IsNullOrEmpty(curVal))
                {
                    value = curVal;
                    break;
                }
            }
            return value;
        }

        private static void BuildPathList(CommandLineParser cmdline, StringCollection target, params string[] args)
        {
            foreach (string arg in args)
                BuildSinglePathList(cmdline, target, arg);
        }

        private static void BuildSinglePathList(CommandLineParser cmdline, StringCollection target, string arg)
        {
            string pathList = cmdline.NamedArguments[arg];
            if (!String.IsNullOrEmpty(pathList))
                target.AddRange(pathList.Split(';'));
        }

        private static void BuildAssemblyPathList(CommandLineParser cmdline, StringCollection target, params string[] args)
        {
            foreach (string arg in args)
            {
                string pathList = cmdline.NamedArguments[arg];
                if (!String.IsNullOrEmpty(pathList))
                {
                    foreach (string s in pathList.Split(';'))
                    {
                        string path = s;
                        if (!s.EndsWith(".dll"))
                            path = String.Concat(s, ".dll");
                        target.Add(path);
                    }
                }
            }
        }
    }
}
